package core;

import java.util.Calendar;
import java.util.GregorianCalendar;
/****************imports****************/
import java.util.Date;

import persistence.dto.ItemDTO;
import persistence.dto.ProductDTO;


/** A bar-coded product that can be stored in a Storage Unit.*/



public class Product extends ModelObject implements Comparable {
    /**
	 * used in Serialization
	 */
	private static final long serialVersionUID = -5030043307647122299L;
	/****************variables****************/
    /** The date this Product was added to the system.*/
    private Calendar creationDate;
    /** Manufacturer's barcode for the Product.*/
    private Barcode barcode;
    /** Textual description of the Product.*/
    private String description;
    /** The size of the Product.*/
    private Amount amount;
    /** 
     * The Product's shelf life, measured in months. 
     * A value of zero means doesn't expire
     */
    private int shelfLife; //number of months
    /** Amount of this product needed for a 3 month supply */
    private int threeMonthSupply;
    
    private boolean updated;
    
    
    /**
     * creates a new productDTO
     * @return a new productDTO 
     */
    public ProductDTO createDTO()
    {
    	return new ProductDTO(getID(), amount.getSize(), amount.getUnit().toString(), 
    			barcode.getBarcode().toString(), creationDate, description,
    			shelfLife, threeMonthSupply);
    }
    
    public boolean isUpdated()
    {
    	return updated;
    }
    public void setUpdated(boolean bool)
    {
    	updated = bool;
    }
    
    
    /****************constructor****************/
    /** 
     * The constructor for a product.  Assumes that the description of this
     * product are both non-empty, that the date is the current date or in the past, 
     * and shelfLife and threeMonthSupply are non-negative.  After this method runs
     * this object will contain all of the data passed into the constructor.
     * 
     * @param creationDate Date when the product was created.
     * @param barcode The barcode from the product
     * @param description A short description of the product
     * @param amount A running amount of the product
     * @param shelfLife how long the product lasts on the shelf
     * @throws IllegalArgumentException If one of the parameters
     * 		is of an illegal type
     */
    public Product(Calendar creationDate, Barcode barcode, 
            String description, Amount amount, int shelfLife, 
            int threeMonthSupply)throws IllegalArgumentException
    {
    	//can't be in the future
    	assert creationDate != null;
    	assert ((new GregorianCalendar().getTimeInMillis()) - creationDate.getTimeInMillis() >= 0);
    	assert barcode != null;
    	assert description != null;
    	assert description.length() > 0;
    	assert amount != null;
    	assert shelfLife >= 0;
    	assert threeMonthSupply >= 0;
    	
    	if ((new GregorianCalendar().getTimeInMillis()) - creationDate.getTimeInMillis() < 0) 
    		throw new IllegalArgumentException();
    	if (description.length() == 0) throw new IllegalArgumentException();
    	if (shelfLife < 0) throw new IllegalArgumentException();
    	if (threeMonthSupply < 0) throw new IllegalArgumentException();
    	
    	this.creationDate = creationDate;
    	this.barcode = barcode;
    	this.description = description;
    	this.amount = amount;
    	this.shelfLife = shelfLife;
    	this.threeMonthSupply = threeMonthSupply;
    	this.updated = false;
    }
    
    /****************methods****************/
    
    /*******getters************/
    
    /** 
     * Returns the creation date of the product 
     *@return A Calendar object containing this products creation date. 
     */
    public Calendar getCreationDate()
    {
        return creationDate;
    }
    
    /**
     * Get the barcode of this product. 
     * @return A Barcode object containing the barcode of the product. 
     */
    public Barcode getBarCode()
    {
        return barcode;
    }
    
    public String getBarcodeString()
    {
    	return barcode.getBarcode();
    }
    
    /**
     * Return the String description of the product. 
     * @return A String containing the description of the product */
    public String getDescription()
    {
        return description;
    }
    
    /**
     * Return the amount of this product. This is the size of the product. 
     * @return A Amount object with the amount/size of the product 
     */
    public Amount getAmount()
    {
        return amount;
    }
    
    /**
     * Return the number of months this product can remain on the shelf
     * before going bad.
     *  
     * @return An int with the shelf life of the product 
     */
    public int getShelfLife()
    {
        return shelfLife;
    }
    
    /** 
     * The number of this product required for a 3-month supply. A value of zero
     * means "unspecified".
     * @return An int with the threMonthSupply of the product */
    public int getThreeMonthSupply()
    {
        return threeMonthSupply;
    }
    
    /********setters*********/
    /** 
     * Sets the creation date of the product.  This value cannot be in the future or
     * (todays date) must be >= d(the date passed in). Otherwise this method will throw
     * an IllegalArgumentException. 
     * 
     * @param d Sets the date the product was added
     * @return true if successful
     * @throws IllegalArgumentException Throws if the input was invalid.
     */
    public boolean setCreationDate(Calendar d)throws IllegalArgumentException
    {
    	assert d != null;
    	//assert ((new Date()).getTime() >= creationDate.getTime());
    	if ((new GregorianCalendar()).compareTo(d) < 0) throw new IllegalArgumentException();
    	//if ((new Date()).getTime() < creationDate.getTime()) throw new IllegalArgumentException();
    	
        creationDate = d;
        return true;
    }
    
    /** 
     * Sets the barcode of the product.
     *  
     * @param b sets the barcode of the description
     * @return true if successful
     * @throws IllegalArgumentException If the parameter b is == null.
     * */
    public boolean setBarCode(Barcode b)throws IllegalArgumentException
    {
    	assert b != null;
    	
    	if (b == null) throw new IllegalArgumentException();
    	
        barcode = b;
        return true;
    }
    
    /** 
     * Sets the textual description of the product.  The parameter for this method 
     * cannot be empty.
     *  
     * @param d Sets the description of the product. Must be non-empty.
     * @return true if successful
     * @throws IllegalArgumentException If the string is empty.
     */
    public boolean setDescription(String d)throws IllegalArgumentException
    {
    	assert d != null;
    	
    	if (d.length() == 0) throw new IllegalArgumentException();
    	
        description = d;
        return true;
    }
    
    /** 
     * Sets the amount of the product.
     *  
     * @param a Sets how much the product contains
     * @return true if successful
     */
    public boolean setAmount(Amount a)
    {
    	assert a != null;
    	
        amount = a;
        return true;
    }
    
    /** 
     * Sets the shelf life of the product. This value must be non-negative.  A value
     * of zero means unspecified.
     *  
     * @param sl non-negative number of months
     * @return true if successful
     * @throws IllegalArgumentException If the parameter sl is negative.
     * */
    public boolean setShelfLife(int sl)throws IllegalArgumentException
    {
    	assert(sl > -1);
    	if (sl < 0) throw new IllegalArgumentException();
    	
        shelfLife = sl;
        return true;
    }
    
    /** 
     * Sets the 3 months supply of the product.  This value must be non-negative. A 
     * Value of zero means that the three-month supply is unspecified.
     *  
     * @param tms non-negative number of months
     * @return true if successful
     * @throws Exception*/
    public boolean setThreeMonthSupply(int tms)throws IllegalArgumentException
    {
    	assert(tms>-1);
    	if (tms < 0) throw new IllegalArgumentException();
    	
        threeMonthSupply = tms;
        return true;
    }
    
    @Override
    /**
     * Override of the equals operator
     */
    public boolean equals(Object obj)
    {
    	assert(obj!=null);
    	if (obj == null) return false;
    	if (obj == this) return true;
    	if (obj.getClass() != this.getClass()) return false;
    	
    	Product prodToTest = (Product) obj;
    	
    	return (prodToTest.getBarCode().equals(this.getBarCode()));
    }
    
    @Override
    /**
     * override of the hashcode method
     */
    public int hashCode()
    {
    	return this.getBarCode().hashCode();
    }

	@Override
	public int compareTo(Object o)
	{
		Product p = (Product)o;
		return this.description.compareTo(p.getDescription());
	}
}
